#pragma once

#include "index.hpp"
#include "util.hpp"
#include <iostream>
#include <algorithm>
#include <jsoncpp/json/json.h>


namespace ns_searcher {

    struct InvertedElemPrint{
        uint64_t doc_id;
        int weight;
        std::vector<std::string> words;
        InvertedElemPrint():doc_id(0),weight(0){}//为什么需要--，
    };
class Searcher {
private:
        ns_index::Index *index;

public:
    Searcher() {}
    ~Searcher() {}

public:
    void InitSearcher(const std::string &input) 
    {
        index = ns_index::Index::GetInstance();
        std::cout << "获取index单例成功..." << std::endl;
        index->BuildIndex(input);
        std::cout << "建立正排和倒排索引成功..." << std::endl;
    }

    std::string GetDesc(const std::string &html_content,const std::string &word)
    {
        //首次出现的位置，前面有50个字节，更新start，往后取100个字节，如若没有，到end就行
        const int prev_step = 50;
        const int next_step = 100;

        auto iter = std::search(html_content.begin(), html_content.end(), word.begin(), word.end(),\
        [](int x,int y){ return (std::tolower(x) == std::tolower(y)); });
        
        if(iter==html_content.end())
        {
            return "None1";
        }
        int pos = std::distance(html_content.begin(),iter);

        int start=0;
        int end = html_content.size()-1;

        if(pos-prev_step > start) start = pos-prev_step;
        if(pos + next_step < end) end = pos + next_step;
        
        if(start>=end) return "None2";
        std::string desc = html_content.substr(start,end-start);
        desc += "...";
        // std::cout<<desc<<std::endl;
        return desc;
        
    }
    void Search(const std::string &query,std::string *json_string) 
    {
        std::vector<std::string> words;
        ns_util::JiebaUtil::CutForString(query,&words);//对搜索词也要分词

        std::vector<InvertedElemPrint> inverted_list_all;
        std::unordered_map<uint64_t,InvertedElemPrint> tokens_map;
        //搜索词分解的字词-以每个字词为单位元
        for(std::string word:words)
        {
            boost::to_lower(word);

            //和分解字词作为键，获取倒排索引拉取的值
            ns_index::InvertedList *inverted_list = index->GetInvertedList(word);
            if(nullptr == inverted_list)
            {
                continue;
            }


            //对拉取的文档内容管理，构造目标格式
            for(const auto & elem:*inverted_list)
            {   
                auto &item=tokens_map[elem.doc_id];

                item.doc_id=elem.doc_id; //item一定是doc_id相同的print节点 ？-就是这样建立倒排的 
                item.weight += elem.weight;//?出现的次数
                item.words.push_back(elem.word);//?倒排索引拉取文档的键
            }
            for(const auto &item:tokens_map)
            {
                inverted_list_all.push_back(std::move(item.second));
            }
            //根据优先级排序--weight
            std::sort(inverted_list_all.begin(), inverted_list_all.end(),\
            [](const InvertedElemPrint &e1,const InvertedElemPrint &e2)
            {
                return e1.weight > e2.weight;
            });
            //以每个字词对应的文档为单元组，拼接出最终结果
            Json::Value root;
            for(auto &item : inverted_list_all)
            {
                ns_index::DocInfo* doc = index->GetForwardIndex(item.doc_id);//正排ID与倒排ID相同
                if(nullptr == doc)
                {
                    continue;
                } 
                Json::Value elem;
                elem["title"] = doc->title;
                elem["desc"] = GetDesc(doc->content,item.words[0]);
                elem["url"] = doc->url;
                elem["id"] = (int)item.doc_id;
                elem["weight"]=item.weight;//int->string ?

                root.append(elem);
            }
            Json::StyledWriter writer;
            // Json::FastWriter writer;
            *json_string = writer.write(root);
            
        }

    }
    
    };
} 
/*
使用未初始化变量的风险包括未定义行为、逻辑错误、程序崩溃和安全漏洞。
确保在使用变量之前对其进行初始化是良好的编程实践，有助于提高代码的安全性和可靠性。
*/